iT邦幫忙

2024 iThome 鐵人賽

DAY 29
0
Mobile Development

從 SwiftUI 到 Apple Vision Pro - SwiftUI 從零開始系列 第 29

從 SwiftUI 到 Apple Vision Pro - SwiftUI 從零開始 Day29

  • 分享至 

  • xImage
  •  

Day29 空間環景照片

目前在空間運算當中,沉浸式的觀賞照片或者影片,是一個全新體驗空間運算的特別功能之一。這個單元來討論如何將照片置入空間當中。

首先,先準備一張360度的照片,匯入到專案:

https://ithelp.ithome.com.tw/upload/images/20240828/201626072smgEtOC2b.png

讀取這張照片:

struct ImmersiveView: View {
    
    @State var textureRequest: AnyCancellable?
    
    var body: some View {
        RealityView { content in
            let rootEntity = Entity()
            
            textureRequest = TextureResource.loadAsync(named: "photo").sink { (error) in
                print(error)
            } receiveValue: { (texture) in
                var material = UnlitMaterial()
                material.color = .init(texture: .init(texture))
                rootEntity.components.set(ModelComponent(
                    mesh: .generateSphere(radius: 1E3),
                    materials: [material]
                ))
                rootEntity.scale *= .init(x: -1, y: 1, z: 1)
                rootEntity.transform.translation += SIMD3<Float>(0.0, 1.0, 0.0)
            }
            
            content.add(rootEntity)
        }
    }
}

程式碼逐行解說:

textureRequest = TextureResource.loadAsync(named: "photo"):使用非同步方式讀取照片名稱為photo的資源,並將其分配給textureRequest。TextureResource.loadAsync方法返回一個 AnyPublisher,可以被sink訂閱。

如果讀取成功,則會使用receiveValue這個call back回傳結果。

var material = UnlitMaterial():新增一個未上色的材質,且該材質不會受到燈光影響。

material.color = .init(texture: .init(texture)):將讀取到的資源初始化給顏色的屬性。

rootEntity.components.set:新增了一個半徑為1E3的球體,並且將材質設定剛剛所建立的material。

rootEntity.scale = .init(x: -1, y: 1, z: 1):將rootEntity的縮放沿x軸翻轉,使得球體的內部朝外。

rootEntity.transform.translation += SIMD3(0.0, 1.0, 0.0):將rootEntity向上移動1。

回到程式進入點,在ImmersiveSpace加入屬性immersionStyle:

ImmersiveSpace(id: "ImmersiveSpace") {
    ImmersiveView()
}
.immersionStyle(selection: .constant(.progressive), in: .progressive)

如果要修改為360環景,則修改immersionStyle屬性為full:

ImmersiveSpace(id: "ImmersiveSpace") {
    ImmersiveView()
}
.immersionStyle(selection: .constant(.full), in: .full)

開啟App之後:

https://ithelp.ithome.com.tw/upload/images/20240828/20162607kkSrUViUoA.png

打開開關,圖片就會放置於整個空間了:

https://ithelp.ithome.com.tw/upload/images/20240828/201626075JyDMn7Ozl.png

完整程式碼。

程式進入點:

@main
struct TestVisionApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        
        ImmersiveSpace(id: "ImmersiveSpace") {
            ImmersiveView()
        }
        .immersionStyle(selection: .constant(.progressive), in: .progressive)
    }
}

視窗View:

import SwiftUI
import RealityKit
import RealityKitContent

struct ContentView: View {
    
    @State private var showImmersiveSpace = false
    
    @Environment(\.openImmersiveSpace) var openImmersiveSpace
    @Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace
    
    var body: some View {
        VStack {
            Toggle("Show ImmersiveSpace", isOn: $showImmersiveSpace)
                .font(.title)
                .frame(width: 360)
                .padding(24)
                .glassBackgroundEffect()
        }
        .padding()
        .onChange(of: showImmersiveSpace) { _, newValue in
            Task {
                if newValue {
                    await openImmersiveSpace(id: "ImmersiveSpace")
                }
                else {
                    await dismissImmersiveSpace()
                }
            }
        }
    }
}

場景View:

import SwiftUI
import RealityKit
import Combine

struct ImmersiveView: View {
    
    @State var textureRequest: AnyCancellable?
    
    var body: some View {
        RealityView { content in
            let rootEntity = Entity()
            
            textureRequest = TextureResource.loadAsync(named: "photo").sink { (error) in
                print(error)
            } receiveValue: { (texture) in
                var material = UnlitMaterial()
                material.color = .init(texture: .init(texture))
                rootEntity.components.set(ModelComponent(
                    mesh: .generateSphere(radius: 1E3),
                    materials: [material]
                ))
                rootEntity.scale *= .init(x: -1, y: 1, z: 1)
                rootEntity.transform.translation += SIMD3<Float>(0.0, 1.0, 0.0)
            }
            
            content.add(rootEntity)
        }
    }
}

從 SwiftUI 到 Apple Vision Pro - SwiftUI 從零開始 Day29 [完]


上一篇
從 SwiftUI 到 Apple Vision Pro - SwiftUI 從零開始 Day28
下一篇
從 SwiftUI 到 Apple Vision Pro - SwiftUI 從零開始 Day30
系列文
從 SwiftUI 到 Apple Vision Pro - SwiftUI 從零開始30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言